package calao.storage;

import java.io.PrintWriter;

public class DataPrinter 
extends DataWriter
{
	
	static final String NULL_ID = "null";
	
	static class Context {
		int fieldCount = 0;
		final Context parent;
		Context(Context parent) {
			this.parent = parent;
		}
	}
	
	Context context = new Context(null);
	
	final PrintWriter writer;
	
	public DataPrinter(PrintWriter writer)
	{
		this.writer = writer;	
	}

	@Override
	public void write(int value) 
	{
		startField();
		writer.print(value);
	}

	@Override
	public void write(long value) 
	{
		startField();
		writer.print(value);
	}

	@Override
	public void write(double value) 
	{
		startField();
		writer.print(value);
	}

	@Override
	public void write(String value) 
	{
		if (value==null) writeId(NULL_ID);
		else {
			startField();
			printStringValue(writer, value);
		}
	}

	@Override
	public void write(boolean value) 
	{
		startField();
		writer.print(value);
	}
	
	public void write(int[] array)
	{
		markArrayStart();
		for (int val : array) write(val);
		markArrayEnd();
	}
	
	public void write(Object[] array)
	{
		markArrayStart();
		for (Object val : array) write(val);
		markArrayEnd();
	}

	void startField()
	{
		if (context.fieldCount++>0) {
			writer.print(',');
		}
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public void write(Object object) 
	{
		if (object==null) writeId(NULL_ID);
		else {
			DataBinding binding = DataBinding.getBinding(object.getClass());
			if (binding==null) writeId("?");
			else {
				markObjectStart();
				binding.write(this, object);
				markObjectEnd();
			}
		}
	}
	
	void writeId(String id)
	{
		startField();
		writer.print(id);
	}
	
	void markObjectStart()
	{
		startField();
		context = new Context(context);
		writer.print('{');		
	}
	
	void markObjectEnd()
	{
		writer.print('}');		
		context = context.parent;		
	}
	
	void markArrayStart()
	{
		startField();
		context = new Context(context);
		writer.print('[');		
	}
	
	void markArrayEnd()
	{
		writer.print(']');		
		context = context.parent;		
	}

	@Override
	public void markChildObjectStart() 
	{
		markObjectStart();
	}

	@Override
	public void markChildObjectEnd() 
	{
		markObjectEnd();
	}
	
	static void printStringValue(PrintWriter writer, String value)
	{
		writer.print('"');
		for (int i=0; i<value.length(); i++) {
			char c = value.charAt(i);
			switch (c) {
			case '\n':
				writer.print("\\n");
				break;
			case '\t':
				writer.print("\\t");
				break;
			case '\r':
				writer.print("\\r");
				break;
			case '"':
				writer.print("\\\"");
				break;
			case '\\':
				writer.print("\\\\");
				break;
			default:
				writer.print(c);
			}
		}
		writer.print('"');
	}

}
